package com.baseframe.auth.config;

import com.baseframe.auth.constant.BaseAuthConstant;
import com.baseframe.auth.granter.BaseTokenGranterConfiguration;
import com.baseframe.auth.service.BaseClientDetailsServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableAuthorizationServer //自动装配授权服务
@AllArgsConstructor
public class BaseAuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private final DataSource dataSource;//数据源

    private  TokenStore tokenStore;//令牌生成策略

    private  AuthenticationManager authenticationManagerBean;//认证管理器

    private  UserDetailsService userDetailsService;//登录逻辑处理

    private  JwtAccessTokenConverter jwtAccessTokenConverter;//jwt令牌解析

    private  TokenEnhancer jwtTokenEnhancer;//拓展令牌

    private  PasswordEncoder passwordEncoder;//加密逻辑




    /*
     * 授权码服务配置 单体环境下使用
     * */
    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        //设置授权码模式的授权码如何 存取，暂时采用内存方式
        return new InMemoryAuthorizationCodeServices();
    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security
                .allowFormAuthenticationForClients()
                .tokenKeyAccess("permitAll()")
                .checkTokenAccess("isAuthenticated()")
                .passwordEncoder(passwordEncoder)
        ;

    }

    /**
     * 配置客户端
     * @param clients the client details configurer
     * @throws Exception 异常
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        BaseClientDetailsServiceImpl clientDetailsService = new BaseClientDetailsServiceImpl(dataSource);
        clientDetailsService.setSelectClientDetailsSql(BaseAuthConstant.SELECT_CLIENT_SQL);
        clientDetailsService.setFindClientDetailsSql(BaseAuthConstant.SORT_CLIENT_LIST_SQL);
        clients.withClientDetails(clientDetailsService);
    }

    /**
     * 配置token端点信息
     * @param endpoints the endpoints configurer
     * @throws Exception 异常
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        //获取自定义tokenGranter
        TokenGranter tokenGranter = BaseTokenGranterConfiguration.getTokenGranters(authenticationManagerBean, endpoints);

        //配置端点
        endpoints.tokenStore(tokenStore)
                .authenticationManager(authenticationManagerBean)
                .authorizationCodeServices(authorizationCodeServices())
                .userDetailsService(userDetailsService)
                .tokenGranter(tokenGranter);

        //扩展token返回结果
        if (jwtAccessTokenConverter != null && jwtTokenEnhancer != null) {
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            List<TokenEnhancer> enhancerList = new ArrayList<>();
            enhancerList.add(jwtTokenEnhancer);
            enhancerList.add(jwtAccessTokenConverter);
            tokenEnhancerChain.setTokenEnhancers(enhancerList);
            //jwt增强
            endpoints.tokenEnhancer(tokenEnhancerChain).accessTokenConverter(jwtAccessTokenConverter);
        }


    }
}
